package server.controlleurs.partie;

import java.io.Serializable;
import java.rmi.AccessException;
import java.rmi.AlreadyBoundException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.ArrayList;

import rmi.Constantes;
import rmi.RemoteObserver;
import rmi.UtilitairesRmi;
import server.controlleurs.tour.ITourControlleur;
import server.controlleurs.tour.TourControlleur;
import server.models.equipe.Equipe;
import server.models.equipe.IEquipe;
import server.models.participant.Participant;
import server.models.partie.IPartie;
import server.models.partie.Partie;
import server.models.posteDeTir.IPosteDeTir;
import server.models.posteDeTir.PosteDeTir;
import server.models.tireur.ITireur;
import server.models.tireur.Tireur;

public class PartieControlleur implements Serializable, IPartieControlleur {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private static final String NOM_PREMIERE_EQUIPE = "Équipe Bleu";
	private static final String NOM_DEUXIEME_EQUIPE = "Équipe Rouge";

	private ITourControlleur tourControlleur = null;

	private IPartie partie;
	private ArrayList<Participant> listeParticipants = new ArrayList<Participant>();

	public PartieControlleur()
	{
		initialiserPartie();

		listeParticipants = new ArrayList<Participant>();
		try {
			this.tourControlleur = (ITourControlleur)UtilitairesRmi.getInstance().obtenirEtBind(Constantes.Controlleurs.TOUR, new TourControlleur(partie.getTerrain(), partie.getListeEquipes()));
		} catch (RemoteException | AlreadyBoundException
				| NotBoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	//Getters et setters
	public IPartie getPartie() throws RemoteException {
		return this.partie;
	}
	
	//Méthodes publiques

	public ITourControlleur getTourControlleur() throws RemoteException {
		return tourControlleur;
	}
	/**
	 * Joindre un participant à la partie
	 * @param participant
	 * @throws NotBoundException 
	 * @throws AlreadyBoundException 
	 * @throws Exception
	 */
	public void joindreParticipant(Participant participant) throws RemoteException, AlreadyBoundException, NotBoundException {
		if (this.listeParticipants.size() < 4) {
			this.listeParticipants.add(participant);

			if (this.listeParticipants.size() == 4) {

				this.demandeEquipeAuParticipants();
				this.debuterPartie();
			}
		} else {
			throw new RemoteException("Il y a déjà 4 participants dans la partie");
		}
	}

	private void demandeEquipeAuParticipants() {
		for (Participant part : listeParticipants)
		{
			IEquipe equipeChoisie;
			try {
				equipeChoisie = part.getClient().choisirEquipe(this.partie.getListeEquipes());
				ajouterJoueurAEquipe(equipeChoisie, part);
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (AlreadyBoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (NotBoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	private void debuterPartie() throws RemoteException, AlreadyBoundException, NotBoundException {
		this.tourControlleur.jouerTour();
		
		IEquipe equipe1 = this.partie.getListeEquipes().get(0);
		IEquipe equipe2 = this.partie.getListeEquipes().get(1);
		
		for (ITireur tireur : equipe1.getTireurs()) {
			boolean gagner = equipe2.getScore() < equipe1.getScore();
			tireur.getParticipant().getClient().afficherGagnant(gagner);
		}
		
		for (ITireur tireur : equipe2.getTireurs()) {
			boolean gagner = equipe1.getScore() < equipe2.getScore();
			tireur.getParticipant().getClient().afficherGagnant(gagner);
		}
		
	}
	
	public void ajouterJoueurAEquipe(IEquipe equipe, Participant participant) throws RemoteException, AlreadyBoundException, NotBoundException
	{		
		equipe.ajouterTireur((ITireur)UtilitairesRmi.getInstance().obtenirEtBind(new Tireur(participant, this.partie.getTerrain().getListePostesDeTir())));
	}

	public void retirerParticipant(Participant participant) throws Exception {

	}

	/**
	 * Sélection du poste de tir par une équipe
	 * @param equipe		Équipe qui a sélectionnée une poste de tir
	 * @param posteDeTir	Poste de tir sélectionnée par l'équipe
	 * @throws Exception 
	 */
	public void selectionnerPosteDeTir(ITireur tireur, IPosteDeTir posteDeTir) throws RemoteException {
		if (tireur.estDejaVisiter(posteDeTir)) {
			throw new RemoteException("Le poste de tir a déjà été visité");
		}

		tireur.visiterPosteDeTir(posteDeTir);
		posteDeTir.ajouterTireur(tireur);
	}

	//Méthodes privées
	/**
	 * Initialise la partie
	 */
	private void initialiserPartie()
	{		
		try {
			this.partie = (IPartie)UtilitairesRmi.getInstance().obtenirEtBind(new Partie());
			this.initialiserEquipes();
			this.initialiserPostesDeTir();
		} catch (RemoteException | AlreadyBoundException | NotBoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * Initialiser les équipes
	 * @throws NotBoundException 
	 * @throws AlreadyBoundException 
	 * @throws RemoteException 
	 * @throws AccessException 
	 */
	private void initialiserEquipes() throws AccessException, RemoteException, AlreadyBoundException, NotBoundException {
		this.partie.ajouterEquipe((IEquipe)UtilitairesRmi.getInstance().obtenirEtBind(new Equipe(NOM_PREMIERE_EQUIPE)));
		this.partie.ajouterEquipe((IEquipe)UtilitairesRmi.getInstance().obtenirEtBind(new Equipe(NOM_DEUXIEME_EQUIPE)));
	}

	/**
	 * Initialiser les postes de tir
	 * @throws NotBoundException 
	 * @throws AlreadyBoundException 
	 * @throws RemoteException 
	 * @throws AccessException 
	 */
	private void initialiserPostesDeTir() throws AccessException, RemoteException, AlreadyBoundException, NotBoundException {
		//Initialise 8 postes de tir, numéroté de 1 à 8.
		for (int i = 0; i < 8; i++) {
			this.partie.getTerrain().ajouterPosteDeTir((IPosteDeTir)UtilitairesRmi.getInstance().obtenirEtBind(new PosteDeTir(i + 1)));
		}
	}
}
